
#include <BGroup>
#include "member_BGroup.h"
#include "member_BShape.h"
#include "member_BNode.h"
#include "member_BConstraint.h"

using namespace BWE;

#define member					(*(member_BGroup*)_ptr)
#define member_allocate()		_ptr = new member_BGroup(this)
#define member_release()		delete (member_BGroup*)_ptr

BGroup::BGroup()
{
	member_allocate();
}
BGroup::BGroup(const BString& name) : BObject(name)
{
	member_allocate();
}
BGroup::BGroup(const BGroup& other) : BObject(other)
{
	member_allocate();
	this->copy(other);
}
BGroup::~BGroup()
{

}

void BGroup::copy(const BGroup& other)
{
	member.shapes = group_member(&other)->shapes;
	member.nodes = group_member(&other)->nodes;
	member.constraints = group_member(&other)->constraints;
	member.children = group_member(&other)->children;
}
BGroup* BGroup::clone() const
{
	return new BGroup(*this);
}

void BGroup::setVisible(bool visible)
{
	if (member.visible != visible)
	{
		member.visible = visible;
		this->emit(Signal_Fresh);
	}
}
bool BGroup::visible() const
{
	return member.visible;
}

bool BGroup::empty() const
{
	return member.shapes.empty() && member.nodes.empty() && member.constraints.empty() && member.children.empty();
}
const BSpace& BGroup::space() const
{
	if (member.dirtySpace)
	{
		member.space.reset();
		if (BShape* first = member.shapes.first())
		{
			if (member.space.empty())
				member.space = first->space();
			else
				member.space.expand(first->space());
			for (int i = 1; i < member.shapes.size(); i++)
			{
				member.space.expand(member.shapes[i]->space());
			}
		}
		if (BNode* first = member.nodes.first())
		{
			if (member.space.empty())
				member.space = first->space();
			else
				member.space.expand(first->space());
			for (int i = 1; i < member.nodes.size(); i++)
			{
				member.space.expand(member.nodes[i]->space());
			}
		}
		if (BGroup* first = member.children.first())
		{
			if (member.space.empty())
				member.space = first->space();
			else
				member.space.expand(first->space());
			for (int i = 0; i < member.children.size(); i++)
			{
				member.space.expand(member.children[i]->space());
			}
		}
		member.dirtySpace = false;
	}
	return member.space;
}

bool BGroup::insert(BShape* shape)
{
	if (!shape)
		return false;
	if (shape_member(shape)->group == this)
		return true;
	member.shapes.insert(shape);
	if (shape_member(shape)->group)
		shape_member(shape)->group->remove(shape);
	shape_member(shape)->group = this;
	member.connect(shape, Signal_Fresh, &member_BGroup::slotShapeFresh);
	member.connect(shape, Signal_Dirty, &member_BGroup::slotShapeDirty);
	member.connect(shape, Signal_Flushed, &member_BGroup::slotShapeFlushed);
	member.connect(shape, Signal_Transformed, &member_BGroup::slotShapeTransformed);
	if (member.space.contain(shape->space()))
		member.raiseDirty();
	member.raiseSignal(Signal_Insert, shape);
	return true;
}
bool BGroup::remove(BShape* shape)
{
	if (!shape)
		return false;
	if (shape_member(shape)->group != this)
		return false;
	BHolder<BShape> holder(shape);
	member.disconnect(shape, Signal_Transformed);
	member.disconnect(shape, Signal_Flushed);
	member.disconnect(shape, Signal_Dirty);
	member.disconnect(shape, Signal_Fresh);
	shape_member(shape)->group = 0;
	member.shapes.remove(shape);
	if (member.space.edged(shape->space()))
		member.raiseDirty();
	member.raiseSignal(Signal_Remove, shape);
	return true;
}
bool BGroup::clearShapes()
{
	if (member.shapes.size())
	{
		while (BShape* shape = member.shapes.last())
		{
			remove(shape);
		}
		return true;
	}
	return false;
}

bool BGroup::contain(BShape* shape)
{
	return member.shapes.contain(shape);
}
int BGroup::shapeCount() const
{
	return member.shapes.size();
}
BShape* BGroup::shape(int index) const
{
	return member.shapes(index);
}
BShape* BGroup::shape(const BString& name) const
{
	for (int i = 0; i < member.shapes.size(); i++)
	{
		BShape* shape = member.shapes[i];
		if (shape->name() == name)
			return shape;
	}
	return 0;
}

bool BGroup::insert(BNode* node)
{
	if (!node)
		return false;
	if (node_member(node)->group == this)
		return true;
	member.nodes.insert(node);
	if (node_member(node)->group)
		node_member(node)->group->remove(node);
	node_member(node)->group = this;
	member.connect(node, Signal_Fresh, &member_BGroup::slotNodeFresh);
	member.connect(node, Signal_Dirty, &member_BGroup::slotNodeDirty);
	member.connect(node, Signal_Flushed, &member_BGroup::slotNodeFlushed);
	member.connect(node, Signal_Transformed, &member_BGroup::slotNodeTransformed);
	if (!member.space.contain(node->space()))
		member.raiseDirty();
	member.raiseSignal(Signal_Insert, node);
	return true;
}
bool BGroup::remove(BNode* node)
{
	if (!node)
		return false;
	if (node_member(node)->group != this)
		return false;
	BNodeHolder holder(node);
	member.disconnect(node, Signal_Fresh);
	member.disconnect(node, Signal_Dirty);
	member.disconnect(node, Signal_Flushed);
	member.disconnect(node, Signal_Transformed);
	member.nodes.remove(node);
	node_member(node)->group = 0;
	if (member.space.edged(node->space()))
		member.raiseDirty();
	member.raiseSignal(Signal_Remove, node);
	return true;
}
bool BGroup::clearNodes()
{
	if (member.nodes.size())
	{
		while (BNode* node = member.nodes.last())
		{
			remove(node);
		}
		return true;
	}
	return false;
}

bool BGroup::contain(BNode* node)
{
	return member.nodes.contain(node);
}
int BGroup::nodeCount() const
{
	return member.nodes.size();
}
BNode* BGroup::node(int index) const
{
	return member.nodes(index);
}
BNode* BGroup::node(const BString& name) const
{
	for (int i = 0; i < member.nodes.size(); i++)
	{
		BNode* node = member.nodes[i];
		if (node->name() == name)
			return node;
	}
	return 0;
}

bool BGroup::insert(BConstraint* constraint)
{
	if (!constraint)
		return false;
	if (constraint_member(constraint)->group == this)
		return true;
	member.constraints.insert(constraint);
	if (constraint_member(constraint)->group)
		constraint_member(constraint)->group->remove(constraint);
	constraint_member(constraint)->group = this;
	member.connect(constraint, Signal_Changed, &member_BGroup::slotConstraintChanged);
	member.raiseSignal(Signal_Insert, constraint);
	return true;
}
bool BGroup::remove(BConstraint* constraint)
{
	if (!constraint)
		return false;
	if (constraint_member(constraint)->group != this)
		return false;
	BHolder<BConstraint> holder(constraint);
	member.disconnect(constraint, Signal_Changed);
	member.constraints.remove(constraint);
	constraint_member(constraint)->group = 0;
	member.raiseSignal(Signal_Remove, constraint);
	return true;
}
bool BGroup::clearConstraints()
{
	if (member.constraints.size())
	{
		while (BConstraint* constraint = member.constraints.last())
		{
			remove(constraint);
		}
		return true;
	}
	return false;
}

bool BGroup::contain(BConstraint* constraint)
{
	return member.constraints.contain(constraint);
}
int BGroup::constraintCount() const
{
	return member.constraints.size();
}
BConstraint* BGroup::constraint(int index) const
{
	return member.constraints(index);
}
BConstraint* BGroup::constraint(const BString& name) const
{
	for (int i = 0; i < member.constraints.size(); i++)
	{
		BConstraint* constratin = member.constraints[i];
		if (constratin->name() == name)
			return constratin;
	}
	return 0;
}

bool BGroup::setParent(BGroup* parent)
{
	if (member.parent != parent && parent != this)
	{
		BHolder<BGroup> holder;
		if (member.parent)
		{
			holder = this;
			if (!member.parent->removeChild(this))
				return false;
		}
		if (parent)
		{
			if (!parent->addChild(this))
				return false;
			holder = 0;
		}
		return true;
	}
	return false;
}
const BGroup* BGroup::parent() const
{
	return member.parent;
}
BGroup* BGroup::parent()
{
	return member.parent;
}

bool BGroup::addChild(BGroup* child)
{
	if (child && child != this && !member.children.contain(child))
	{
		member.children.append(child);
		group_member(child)->parent = this;
		if (!member.space.contain(child->space()))
			member.raiseDirty();
		member.raiseSignal(Signal_Insert, child);
		return true;
	}
	return false;
}
bool BGroup::removeChild(BGroup* child)
{
	if (child && child != this && member.children.contain(child))
	{
		BHolder<BGroup> holder(child);
		group_member(child)->parent = 0;
		member.children.remove(child);
		if (!member.space.contain(child->space()))
			member.raiseDirty();
		member.raiseSignal(Signal_Remove, child);
		return true;
	}
	return false;
}
bool BGroup::clearChildren()
{
	if (member.children.size())
	{
		for (int i = 0; i < member.children.size(); i++)
		{
			BGroup* child = member.children[i];
			if (removeChild(child))
				i--;
		}
		return true;
	}
	return false;
}

bool BGroup::contain(BGroup* child)
{
	return member.children.contain(child);
}
int BGroup::childCount() const
{
	return member.children.size();
}
BGroup* BGroup::child(int index) const
{
	return member.children(index);
}
BGroup* BGroup::child(const BString& name) const
{
	for (int i = 0; i < member.children.size(); i++)
	{
		if (member.children[i]->name() == name)
			return member.children[i];
	}
	return 0;
}

void BGroup::update(BReal time)
{

}
